package com.ants.boot.wx.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ants.boot.core.Response;
import com.ants.boot.core.annotation.Log;
import com.ants.boot.core.security.jwt.JwtTokenProvider;
import com.ants.boot.core.security.service.CustomUserDetailsServiceImpl;
import com.ants.boot.core.security.user.JwtUser;
import com.ants.boot.system.domain.SysUser;
import com.ants.boot.system.dto.sysuser.AddUserDto;
import com.ants.boot.system.service.SysUserService;
import com.ants.boot.wx.dto.wxauth.WxBindSysUserDto;
import com.ants.boot.wx.dto.wxauth.WxLoginDto;
import com.ants.boot.wx.properties.WxAppletProperties;
import com.ants.boot.wx.vo.wxauth.WxLoginVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * @author 蚂蚁会花呗
 * @date 2022/4/28 14:46
 * 微信登录授权等功能
 *
 */
@RequestMapping("/wx/auth")
@RestController
@Api(tags = "微信登录绑定")
public class WxAuthController {

    @Autowired
    private WxAppletProperties wxAppletProperties;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    /**
     * spring security 登录实现
     */
    @Autowired
    private CustomUserDetailsServiceImpl sysUserDetailsService;


    /**
     * 小程序绑定，获取openid，
     * 判断是否绑定过，绑定过直接登录，否则后端先注册并登录
     * @param wxBindSysUserDto
     * @return
     */
    @PostMapping("bind")
    @ApiOperation(value="绑定手机号",notes="绑定手机号")
    @Transactional
    public Response bind(@RequestBody @Validated WxBindSysUserDto wxBindSysUserDto){
        String openId = getOpenId(wxBindSysUserDto.getCode());
        SysUser sysUser = sysUserService.findByOpenId(openId);
        if (sysUser == null){
            //绑定新用户并返回前端
            AddUserDto user = new AddUserDto();
            BeanUtils.copyProperties(wxBindSysUserDto,user);
            user.setPassword(new BCryptPasswordEncoder().encode(wxBindSysUserDto.getPassword()));
            user.setOpenid(openId);
            user.setPhoneNumber(wxBindSysUserDto.getUsername());
            sysUserService.addUser(user);
        }
        return Response.ok();
    }

    /**
     * 登录
     * @return
     */
    @PostMapping("login")
    @ApiOperation(value="登录",notes="微信登录")
    @Log(module = "登录",operate = "微信登录")
    @ApiResponses({
            @ApiResponse(code = 200,message = "操作成功！",response = WxLoginVo.class)
    })
    public Response login(@RequestBody WxLoginDto wxLoginDto, HttpServletResponse response){
        String openId = getOpenId(wxLoginDto.getCode());
        SysUser sysUser = sysUserService.findByOpenId(openId);
        String token = jwtTokenProvider.createJwtToken(new JwtUser(sysUser.getId(),sysUser.getUsername()));
        UserDetails userDetails = sysUserDetailsService.loadUserByUsername(sysUser.getUsername());
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                userDetails,null,userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        WxLoginVo vo = new WxLoginVo();
        BeanUtils.copyProperties(sysUser,vo);
        vo.setToken(token);
        response.setHeader("Authorization",token);
        return Response.okData(vo);
    }

    /**
     * 校验登录状态,并判断是否过期，过期刷新token
     * @return
     */
    @PostMapping("check_login")
    @ApiOperation(value="校验登录状态",notes="微信登录校验登录状态")
    @ApiResponses({
            @ApiResponse(code = 200,message = "操作成功！",response = WxLoginVo.class)
    })
    public Response checkLogin(HttpServletRequest request){
        String token = getJwtToken(request);
        if (token != null && jwtTokenProvider.validateToken(token)){
            //判断是否登录超时
            Map<String,Object> map = jwtTokenProvider.isTokenExpiredAndRefreshToken(token);
            if (!map.isEmpty()){
                if (Boolean.parseBoolean(map.get("status").toString())){
                    if (map.containsKey("token")){
                        token = map.get("token").toString();
                        String username = jwtTokenProvider.getUserNameFromToken(token);
                        UserDetails userDetails = sysUserDetailsService.loadUserByUsername(username);
                        Authentication authentication = new UsernamePasswordAuthenticationToken(
                                userDetails,null,userDetails.getAuthorities());
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                        SysUser sysUser = sysUserService.findByUsername(username);
                        WxLoginVo vo = new WxLoginVo();
                        BeanUtils.copyProperties(sysUser,vo);
                        vo.setToken(token);
                        return Response.okData(vo);
                    }
                }
                return Response.ok();
            }


        }
        return Response.fail("校验失败！");
    }

    /**
     * 获取openid
     * @param code
     * @return
     */
    private String getOpenId(String code){
        String url = wxAppletProperties.getOpenIdUrl() +
                "appid=" + wxAppletProperties.getAppId() +
                "&secret=" + wxAppletProperties.getSecret() +
                "&js_code=" + code +
                "&grant_type=authorization_code";
        String jsonData = restTemplate.getForObject(url, String.class);
        JSONObject data = JSON.parseObject(jsonData);
        return data.getString("openid");
    }


    /**
     * 获取header 中的  Authorization
     * @param request
     * @return
     */
    protected String getJwtToken(HttpServletRequest request) {
        String authInfo = request.getHeader("Authorization");
        return StringUtils.removeStart(authInfo, "Bearer ");
    }


}
